package com.erp.framework.util;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.StringTokenizer;

import com.erp.framework.SimpleConstants;
import com.erp.framework.util.logger.Logger;

public class StringUtil implements SimpleConstants {

	static public String CONCATE_CHAR = "/";

	/**
	 * Escape character c in string s. Each occurence of c will be doubled. StringUtil.escape("abcd", "d") will return "abcdd".
	 */
	static public String escape(String s, char c) {

		return replace(s, String.valueOf(c), String.valueOf(c) + String.valueOf(c));
	}

	/**
	 * Escape character c in string s by a slash. Each occurence of c will be slashed. StringUtil.escapeSlash("abcd", "d") wil
	 * return "abc\d"
	 */
	static public String escapeSlash(String s, char c) {

		return replace(s, String.valueOf(c), "\\" + c);
	}

	static public String escapeSlash(String s, String c) {

		return replace(s, String.valueOf(c), "\\" + c);
	}

	/**
	 * Repace each occurence of oldStr in s by newStr.
	 * 
	 * @param s
	 *            Source string.
	 * @param oldStr
	 *            Target to be replaced.
	 * @param newStr
	 *            New string to replace.
	 * @return A string with oldStr replaced by newStr.
	 */
	static public String replace(String s, String oldStr, String newStr) {

		if (null == oldStr || oldStr.length() < 1) // Fix for infinity
			// loop......that result in
			// out of memory exception.
			// 2003-09-17
			return s;
		StringBuffer sb = new StringBuffer();
		int i = 0, lasti = 0, nOldStr = oldStr.length();
		while (-1 != (i = s.indexOf(oldStr, i))) {
			sb.append(s.substring(lasti, i));
			sb.append(newStr);
			i += nOldStr;
			lasti = i;
		}
		sb.append(s.substring(lasti, s.length()));
		return sb.toString();
	}

	/**
	 * Make a call to escape(Object[], char) and then call to concateString(Object[]).
	 */
	static public String concateStringEscaped(Object[] objs, char c) {

		escape(objs, c);
		return concateString(objs);
	}

	/**
	 * Escape the elements of objs using the escape(String s, char c) method.
	 * 
	 * @param objs
	 * @param c
	 */

	static public void escape(Object objs[], char c) {

		for (int i = 0; i < objs.length; i++)
			objs[i] = stringRpl("" + objs[i], String.valueOf(c), String.valueOf(c) + String.valueOf(c));
	}

	/**
	 * Repace each occurence of oldStr in s by newStr. Developer need to check if the input string is null.
	 * 
	 * @param str -
	 *            Source string.
	 * @param oldStr -
	 *            Target to be replaced.
	 * @param replstr -
	 *            New string to replace.
	 * @return A string with oldStr replaced by newStr.
	 */
	// same as replace
	public static String stringRpl(String str, String oldStr, String replstr) {
		if (null == oldStr || oldStr.length() < 1)
			return str;
		StringBuffer sb = new StringBuffer();
		int i = 0, lasti = 0, nOldStr = oldStr.length();
		while (-1 != (i = str.indexOf(oldStr, i))) {
			sb.append(str.substring(lasti, i));
			sb.append(replstr);
			i += nOldStr;
			lasti = i;
		}
		sb.append(str.substring(lasti, str.length()));
		return sb.toString();
	}

	// same as replace and original stringRpl
	public static String replaceFirst(String instring, String replstr, String replstr1) {
		int length = instring.length();
		int length1 = replstr.length();
		int pos = instring.indexOf(replstr);
		String new_string = "";
		String cut_string = instring;
		if (pos >= 0) {
			new_string += cut_string.substring(0, pos);
			new_string += replstr1;
			cut_string = cut_string.substring(pos + length1);
			pos = cut_string.indexOf(replstr);
		}

		String full_string = new_string + cut_string;
		return full_string;
	}

	/**
	 * Developer need to check if the input string is null.
	 * 
	 * @param sPrefix
	 * @param objs
	 * @param sPostfix
	 * @return empty string if the object is null.
	 */
	public static String arrayString(String sPrefix, Object[] objs, String sPostfix) {

		if (null == objs || objs.length < 1)
			return "";
		String s = sPrefix + objs[0];
		for (int i = 1; i < objs.length; i++)
			s += ", " + objs[i];
		s += sPostfix;
		return s;
	}

	/**
	 * Concate the elements of objs using sMiddle.
	 * 
	 * @param objs
	 *            An array of String.
	 * @param sMiddle
	 *            The connection string between each elements.
	 * @return Suppose objs contains { "a", "b", "c" } and sMiddle is ",", the return string will be "a,b,c". If the objs is null,
	 *         return empty string
	 */
	static public String concateString(Object[] objs, String sMiddle) {

		if (null == objs || objs.length < 1)
			return "";
		// String s = ConvertUtil.objToString(objs[0], false);
		String s = CommonUtil.nullToString(objs[0]);
		for (int i = 1; i < objs.length; i++)
			s += sMiddle + CommonUtil.nullToString(objs[i]);
		return s;
	}

	/**
	 * Concate objs using CONCATE_CHAR.
	 */
	static public String concateString(Object[] objs) {

		return concateString(objs, CONCATE_CHAR);
	}

	/**
	 * Make a call to escape(Object[], char) and then call to concateString(Object[]).
	 */
	static public String concateString(Object[] objs, char c) {

		escape(objs, c);
		return concateString(objs);
	}

	/**
	 * Strip the name returned by "Object.getClassName()" to only the class name. ie. The right most portion of a dotted name or
	 * the name itself if the class doesn't belong to any package.
	 * 
	 * @param str
	 *            A string returned by Object.getClassName().
	 * @return The right most portion of a dotted name. eg. "VUtil.StringUtil" -> "StringUtil". If the input string is null,
	 *         return an empty string.
	 */
	public static String getClassName(String str) {

		return str == null ? "" : str.substring(str.lastIndexOf(".") + 1, str.length());
	}

	/**
	 * Developer need to check if the input string is null. Trim empty lines and replace carriage return '\r' to nothing. This is
	 * specially designed for iText's report.
	 */
	public static String chops(String str) {

		StringBuffer sb = new StringBuffer();
		StringTokenizer st = new StringTokenizer(str, "\n");
		while (st.hasMoreTokens()) {
			str = st.nextToken();
			if (str.trim().length() != 0)
				sb.append(str + "\n");
		}

		return stringRpl(sb.toString(), "\r", "");
	}

	/**
	 * Developer need to check if the input string is null.
	 * 
	 * @param str
	 * @param numOfDecimal
	 * @return
	 */
	public static String chopDecimalPlaces(String str, int numOfDecimal) {
		int dotIndex = -1;

		if (!NumberUtil.isValidNumber(str)) {
			return str;
		}

		dotIndex = str.indexOf(".");
		if (dotIndex == -1) {
			return str;
		}

		if ((str.length() - dotIndex) < (numOfDecimal + 1)) {
			return str;
		}

		return str.substring(0, dotIndex + numOfDecimal + 1);
	}

	/**
	 * @param str
	 * @param enc
	 * @return
	 */
	public static String encodeString(String str, String enc) {
		if (str == null)
			return null;
		try {
			return new String(str.getBytes(enc), "8859_1");
		} catch (java.io.UnsupportedEncodingException nse) {
			return str;
		}
	}

	/**
	 * @param str
	 * @param enc
	 * @return
	 */
	public static String decodeString(String str, String enc) {
		if (str == null)
			return null;
		try {
			return new String(str.getBytes("8859_1"), enc);
		} catch (java.io.UnsupportedEncodingException nse) {
			return str;
		}
	}

	/**
	 * @param str
	 * @return if the input string is null, return false.
	 */
	public static boolean isZeroString(String str) {
		if (str == null)
			return false;
		for (int i = 0; i < str.length(); i++) {
			if (str.charAt(i) != '0') {
				return false;
			}
		}
		return true;
	}

	/**
	 * @param inNum
	 * @param formatMask
	 * @return null if the input string or the format mask is null.
	 */
	public static String formatNumberStr(String inNum, String formatMask) {
		if (CommonUtil.isEmpty(inNum))
			return "";

		if (!NumberUtil.isValidNumber(inNum)) {
			return inNum;
		}

		if (CommonUtil.isEmpty(formatMask))
			return "";

		DecimalFormat myFormatter = new DecimalFormat(formatMask);
		String formattedStr = myFormatter.format(new Double(inNum).doubleValue());
		// Logger.cruise(new CommonUtil(), "formatNumberStr(), formattedStr=" + formattedStr);
		return formattedStr;
	}

	/**
	 * @param str
	 * @param numOfSpace
	 * @return empty string if the input string is null or empty.
	 */
	public static String addLeadingSpace(String str, int numOfSpace) {
		String temp = "";

		str = ConvertUtil.nullToString(str);

		if (numOfSpace <= 0) {
			return str;
		}

		for (int i = 0; i < numOfSpace; i++) {
			temp += " ";
		}

		return (temp + str);
	}

	/**
	 * @param num_str
	 * @return empty string if the input string is null.
	 */
	public static String toWords(String num_str) {
		if (num_str == null)
			return "";
		int num_str_len = num_str.length();
		if (num_str_len > 6) {
			return toWords(num_str.substring(0, num_str_len - 6)) + "Million " + toWords(num_str.substring(num_str_len - 6));
		} else if (num_str_len > 3) {
			return ((isZeroString(num_str.substring(0, num_str_len - 3))) ? "" : toWords(num_str.substring(0, num_str_len - 3))
					+ "Thousand ")
					+ toWords(num_str.substring(num_str_len - 3));
		} else if (num_str_len > 2) {
			return ((isZeroString(num_str.substring(0, num_str_len - 2))) ? "" : toWords(num_str.substring(0, num_str_len - 2))
					+ "Hundred ")
					+ toWords(num_str.substring(num_str_len - 2));
		} else if (num_str_len == 2) {
			if (num_str.charAt(0) == '1' && num_str.charAt(1) != '0') {
				switch (num_str.charAt(1)) {
				case '1':
					return "Eleven ";
				case '2':
					return "Twelve ";
				case '3':
					return "Thirteen ";
				case '4':
					return "Fourteen ";
				case '5':
					return "Fifteen ";
				case '6':
					return "Sixteen ";
				case '7':
					return "Seventeen ";
				case '8':
					return "Eighteen ";
				case '9':
					return "Nineteen ";
				default:
					return " ";
				}
			} else {
				switch (num_str.charAt(0)) {
				case '0':
					return toWords(num_str.substring(1));
				case '1':
					return "Ten ";
				case '2':
					return "Twenty " + toWords(num_str.substring(1));
				case '3':
					return "Thirty " + toWords(num_str.substring(1));
				case '4':
					return "Forty  " + toWords(num_str.substring(1));
				case '5':
					return "Fifty " + toWords(num_str.substring(1));
				case '6':
					return "Sixty " + toWords(num_str.substring(1));
				case '7':
					return "Seventy " + toWords(num_str.substring(1));
				case '8':
					return "Eighty " + toWords(num_str.substring(1));
				case '9':
					return "Ninety " + toWords(num_str.substring(1));
				default:
					return " ";
				}
			}
		} else {
			switch (num_str.charAt(0)) {
			case '1':
				return "One ";
			case '2':
				return "Two ";
			case '3':
				return "Three ";
			case '4':
				return "Four ";
			case '5':
				return "Five ";
			case '6':
				return "Six ";
			case '7':
				return "Seven ";
			case '8':
				return "Eight ";
			case '9':
				return "Nine ";
			default:
				return " ";
			}
		}
	}

	/**
	 * @param number_str
	 * @return empty string if the input string is null or empty.
	 */
	public static String convertNumToStr(String number_str) {
		if (CommonUtil.isEmpty(number_str))
			return "";

		BigDecimal num = null;
		try {
			num = new BigDecimal(number_str);
		} catch (Exception e) {

			System.err.println("Invalid number string: " + e.getMessage());
			return null;
		}

		String integral_part = String.valueOf(num.intValue());
		String tmp = num.setScale(2, BigDecimal.ROUND_HALF_UP).toString();
		String fractional_part = tmp.substring(tmp.length() - 2);
		// System.out.println("converting "+integral_part+" . "+fractional_part);
		if (integral_part.length() > 9) {
			return number_str;
		}

		if (isZeroString(number_str)) {
			return "Zero";
		} else if (!isZeroString(fractional_part)) {
			return toWords(integral_part) + " And Cents " + toWords(fractional_part).trim();
		} else {
			// insert an "And"
			StringBuffer buf = new StringBuffer(toWords(integral_part).trim());
			String partial = null;
			// System.out.println("Got str = "+buf.toString());
			boolean okayed = false;
			int pos = 0;
			for (int i = 0, j; i < integral_part.length(); i++) {
				j = integral_part.length() - i - 1;
				// System.out.println("Trying: "+integral_part.substring(j));
				partial = toWords(integral_part.substring(j)).trim();
				if (partial.length() < buf.length() && partial.length() > 1) {
					// System.out.println("Comparing: <"+partial+"> with <"+buf.substring(buf.length()-partial.length())+"> ");
					if (partial.equals(buf.substring(buf.length() - partial.length()))) {
						if (i == 0) {
							okayed = true;
							pos = buf.length() - partial.length();
						} else {
							if (isAndNeeded(Integer.parseInt(integral_part))) {
								if (i > 1 && okayed)
									buf.insert(pos, "And ");
								buf.insert(buf.length() - partial.length(), "And ");
								okayed = false;
							}
							break;
						}
					}
				}
			}

			if (isAndNeeded(Integer.parseInt(integral_part))) {
				if (okayed && integral_part.length() > 2)
					buf.insert(pos, "And ");
			}
			return buf.toString();
		}
	}

	private static boolean isAndNeeded(int x) {
		boolean needAnd = true;
		double epsilon = 0.0000000001;

		int numOfPlace = (int) Math.floor(Math.log((double) x) / Math.log(10.0)) + 1;

		int maxNum = (numOfPlace / 3) * 3;

		double pow = Math.pow(10.0, (double) maxNum);

		double y = x / pow;

		double diff = Math.abs(y - ((int) y));

		if (diff < epsilon) {
			int remainder = numOfPlace % 3;

			if (remainder == 2) {
				needAnd = false;
			}
		}

		return needAnd;
	}

	/**
	 * Developer need to check if the input string is null.
	 * 
	 * @param str
	 * @param numOfSpace
	 * @return
	 */
	public static String addTrailingSpace(String str, int numOfSpace) {
		String temp = "";
		str = ConvertUtil.nullToString(str);
		if (numOfSpace <= 0) {
			return str;
		}

		for (int i = 0; i < numOfSpace; i++) {
			temp += " ";
		}

		return (str + temp);
	}

	/**
	 * Developer need to check if the input string is null.
	 * 
	 * @param str
	 * @param delim
	 * @return
	 */
	public static String[] split(String str, String delim) {
		StringTokenizer st = new StringTokenizer(str, delim);
		int count = st.countTokens();
		if (count <= 0) {
			return null;
		}

		String[] returnStr = new String[count];
		int i = 0;

		while (st.hasMoreTokens()) {
			returnStr[i++] = st.nextToken();
		}

		return returnStr;
	}

	/**
	 * @param str
	 * @return null if the string is null.
	 */
	public static String sqlEncode(String str) {
		if (str == null)
			return null;

		return stringRpl(str, "'", "''");
	}

	/**
	 * @param str1
	 * @param str2
	 * @return true if both input strings are null or their values are equal.
	 */
	public static boolean stringEquals(String str1, String str2) {
		if (str1 == null && str2 == null)
			return true;
		else {
			if ((str1 == null && str2 != null) || (str1 != null && str2 == null))
				return false;
			else {
				if ((str1.equals(str2)) && (str2.equals(str1)))
					return true;
				else
					return false;
			}
		}
	}

	/**
	 * @param str1
	 * @param str2
	 * @return true if both input strings are null or their values are equal.
	 */
	public static boolean stringEqualsIgnoreCase(String str1, String str2) {
		if (str1 == null && str2 == null)
			return true;
		else {
			if ((str1 == null && str2 != null) || (str1 != null && str2 == null))
				return false;
			else {
				if ((str1.equalsIgnoreCase(str2)) && (str2.equalsIgnoreCase(str1)))
					return true;
				else
					return false;
			}
		}
	}

	/**
	 * @param str
	 * @return true if the string is null or empty or zero
	 */
	public static boolean strIsZeroOrEmpty(String str) {
		if (CommonUtil.isEmpty(str))
			return true;
		if (SimpleConstants.STRING_ZERO.equals(str)) {
			return true;
		}
		return false;
	}

	/**
	 * 
	 * @param str
	 * @return empty string if the input string is null or empty
	 */
	public static String formatDateStr(String str) {
		if (CommonUtil.isEmpty(str)) {
			return "";
		}
		SimpleDateFormat sdf = new SimpleDateFormat(SimpleConstants.OUTPUT_DATE_FORMAT);
		return sdf.format(java.sql.Date.valueOf(str));
	}

	/**
	 * @param str
	 * @param format
	 * @return empty string if the input string is null or empty
	 */
	public static String formatDateStr(String str, String format) {
		if (CommonUtil.isEmpty(str)) {
			return "";
		}

		SimpleDateFormat sdf = new SimpleDateFormat(SimpleConstants.OUTPUT_DATE_FORMAT);
		if (!CommonUtil.isEmpty(format)) {
			sdf = new SimpleDateFormat(format);
		}

		return sdf.format(java.sql.Date.valueOf(str));
	}

	/**
	 * @param num_str
	 * @return empty string if the input string is null or empty
	 */
	public static String decimalPartsToChiWords(String num_str) {
		if (num_str == null)
			return "";

		int num_str_len = num_str.length();

		if (num_str_len <= 0)
			return "";

		String tenCent = "";
		String cent = "";
		String tenCentWords = "";
		String centWords = "";

		if (num_str_len == 2) {
			tenCent = num_str.substring(0, 1);
			cent = num_str.substring(1, 2);
		} else if (num_str_len == 1) {
			cent = num_str.substring(0, 1);
		}

		if ("0".equals(tenCent)) {
			tenCent = "";
		}

		if ("0".equals(cent)) {
			cent = "";
		}

		tenCentWords = integralPartsToChiWords(tenCent);
		centWords = integralPartsToChiWords(cent);

		if (!"".equals(tenCentWords)) {
			tenCentWords += SimpleConstants.CHI_TEN_CENT;
		}

		if (!"".equals(centWords)) {
			centWords += SimpleConstants.CHI_CENT;
		}

		return tenCentWords + centWords;
	}

	/**
	 * Check if a string has exceeded it's length. It can
	 * 
	 */
	static public boolean exceedLength(String str, int len) {

		if (!CommonUtil.isNothing(str)) {
			// Sybase database uses 3 bytes for storing a chinese character,
			// therefore, i*2 is adjusted
			// for it.
			int i = 0;
			try {
				return str.getBytes("utf-8").length > len;
			} catch (java.io.UnsupportedEncodingException e) {
				return true;
			}
			/*
			 * try { i = s.getBytes("BIG5").length; } catch ( java.io.UnsupportedEncodingException e ) { i = s.length(); } return
			 * s.length() + (i - s.length())*2 > len;
			 */
		}
		return false;
	}

	/**
	 * @param str
	 * @param origFormat
	 * @param destFormat
	 * @return empty string if the input string is null or empty
	 */
	public static String formatDateStr(String str, String origFormat, String destFormat) {
		if (CommonUtil.isEmpty(str) || CommonUtil.isEmpty(origFormat) || CommonUtil.isEmpty(destFormat)) {
			return "";
		}

		SimpleDateFormat origSdf = new SimpleDateFormat(origFormat, SimpleConstants.DEFAULT_LOCALE);
		SimpleDateFormat destSdf = new SimpleDateFormat(destFormat, SimpleConstants.DEFAULT_LOCALE);
		try {
			if (CommonUtil.isValidDate(str, origFormat)) {
				// System.out.println("inStr=" + inStr);
				// System.out.println("origFormat=" + origFormat);
				// System.out.println("destFormat=" + destFormat);
				java.sql.Timestamp origTs = new java.sql.Timestamp(origSdf.parse(str).getTime());
				// System.out.println("origTs=" + origTs);
				return destSdf.format(origTs);
			} else {
				return "";
			}
		} catch (Exception e) {
			Logger.logExceptions(e);
			return "";
		}
	}

	/**
	 * @param num_str
	 * @return empty string if the input string is null or empty
	 */
	public static String integralPartsToChiWords(String num_str) {
		if (num_str == null)
			return "";
		int num_str_len = num_str.length();

		if (num_str_len <= 0)
			return "";

		int lastZeroPos = -1;
		for (int i = 0; i < num_str_len; i++) {
			if ('0' != num_str.charAt(i)) {
				break;
			} else {
				lastZeroPos = i;
			}

		}

		if (lastZeroPos >= 0) {
			return SimpleConstants.CHI_ZERO + integralPartsToChiWords(num_str.substring(lastZeroPos + 1, num_str_len));
		}

		if (num_str_len > 12) {
			if ("000000000000".equals(num_str.substring(num_str_len - 12))) {
				return integralPartsToChiWords(num_str.substring(0, num_str_len - 12)) + SimpleConstants.CHI_TRILLION;
			} else {
				return integralPartsToChiWords(num_str.substring(0, num_str_len - 12)) + SimpleConstants.CHI_TRILLION
						+ integralPartsToChiWords(num_str.substring(num_str_len - 12));
			}
		} else if (num_str_len > 8) {
			if ("00000000".equals(num_str.substring(num_str_len - 8))) {
				return integralPartsToChiWords(num_str.substring(0, num_str_len - 8)) + SimpleConstants.CHI_HUNDRED_MILLION;
			} else {
				return integralPartsToChiWords(num_str.substring(0, num_str_len - 8)) + SimpleConstants.CHI_HUNDRED_MILLION
						+ integralPartsToChiWords(num_str.substring(num_str_len - 8));
			}
		} else if (num_str_len > 4) {
			if ("0000".equals(num_str.substring(num_str_len - 4))) {
				return integralPartsToChiWords(num_str.substring(0, num_str_len - 4)) + SimpleConstants.CHI_TEN_THOUSAND;
			} else {
				return integralPartsToChiWords(num_str.substring(0, num_str_len - 4)) + SimpleConstants.CHI_TEN_THOUSAND
						+ integralPartsToChiWords(num_str.substring(num_str_len - 4));
			}
		} else if (num_str_len > 3) {
			if ("000".equals(num_str.substring(num_str_len - 3))) {
				return integralPartsToChiWords(num_str.substring(0, num_str_len - 3)) + SimpleConstants.CHI_THOUSAND;
			} else {
				return integralPartsToChiWords(num_str.substring(0, num_str_len - 3)) + SimpleConstants.CHI_THOUSAND
						+ integralPartsToChiWords(num_str.substring(num_str_len - 3));
			}
		} else if (num_str_len > 2) {
			if ("00".equals(num_str.substring(num_str_len - 2))) {
				return integralPartsToChiWords(num_str.substring(0, num_str_len - 2)) + SimpleConstants.CHI_HUNDRED;
			} else {
				return integralPartsToChiWords(num_str.substring(0, num_str_len - 2)) + SimpleConstants.CHI_HUNDRED
						+ integralPartsToChiWords(num_str.substring(num_str_len - 2));
			}
		} else if (num_str_len > 1) {
			if ("0".equals(num_str.substring(num_str_len - 1))) {
				return integralPartsToChiWords(num_str.substring(0, num_str_len - 1)) + SimpleConstants.CHI_TEN;
			} else {
				return integralPartsToChiWords(num_str.substring(0, num_str_len - 1)) + SimpleConstants.CHI_TEN
						+ integralPartsToChiWords(num_str.substring(num_str_len - 1));
			}
		} else if (num_str_len == 1) {
			switch (num_str.charAt(0)) {
			case '0':
				return SimpleConstants.CHI_ZERO;
			case '1':
				return SimpleConstants.CHI_ONE;
			case '2':
				return SimpleConstants.CHI_TWO;
			case '3':
				return SimpleConstants.CHI_THREE;
			case '4':
				return SimpleConstants.CHI_FOUR;
			case '5':
				return SimpleConstants.CHI_FIVE;
			case '6':
				return SimpleConstants.CHI_SIX;
			case '7':
				return SimpleConstants.CHI_SEVEN;
			case '8':
				return SimpleConstants.CHI_EIGHT;
			case '9':
				return SimpleConstants.CHI_NINE;
			default:
				return " ";
			}
		} else {
			switch (num_str.charAt(0)) {
			case '1':
				return SimpleConstants.CHI_ONE;
			case '2':
				return SimpleConstants.CHI_TWO;
			case '3':
				return SimpleConstants.CHI_THREE;
			case '4':
				return SimpleConstants.CHI_FOUR;
			case '5':
				return SimpleConstants.CHI_FIVE;
			case '6':
				return SimpleConstants.CHI_SIX;
			case '7':
				return SimpleConstants.CHI_SEVEN;
			case '8':
				return SimpleConstants.CHI_EIGHT;
			case '9':
				return SimpleConstants.CHI_NINE;
			default:
				return " ";
			}
		}
	}

	/**
	 * @param num_str
	 * @return empty string if the input string is null or empty
	 */
	public static String toChiWords(String num_str) {
		if (num_str == null)
			return "";
		BigDecimal num = null;
		try {
			num = new BigDecimal(num_str);
		} catch (Exception e) {
			Logger.logExceptions(e);
			return "";
		}

		double dNum = num.doubleValue();
		double absDNum = Math.abs(dNum);
		String chiWords = "";
		String intPart = "";
		String decPart = "";

		if ((absDNum - 0.0) < SimpleConstants.EPSILON) {
			// regard this as zero
			return SimpleConstants.CHI_ZERO + SimpleConstants.CHI_DOLLAR + SimpleConstants.CHI_ONLY;
		}

		intPart = (((((long) absDNum)) - 0.0) < SimpleConstants.EPSILON) ? "" : String.valueOf((((long) absDNum)));
		decPart = (((absDNum - ((long) absDNum))) < SimpleConstants.EPSILON) ? "" : String.valueOf(Math
				.round((absDNum - ((long) absDNum)) * 100));

		intPart = integralPartsToChiWords(intPart);
		decPart = decimalPartsToChiWords(decPart);

		if (dNum < 0) {
			chiWords += SimpleConstants.CHI_NEGATIVE;
		}

		if (!"".equals(intPart)) {
			intPart += SimpleConstants.CHI_DOLLAR;
		}

		chiWords += intPart;
		chiWords += decPart;
		chiWords += SimpleConstants.CHI_ONLY;

		return chiWords;
	}

	/**
	 * @param str
	 * @return empty string if the input string is null or empty
	 */
	public static String toCSVToken(String str) {
		if (CommonUtil.isEmpty(str))
			return "";

		boolean hasComma = (str.indexOf(',') != -1);
		boolean hasDQuote = (str.indexOf('"') != -1);

		if (!hasComma && !hasDQuote)
			return str;

		StringBuffer sb = new StringBuffer(str);
		if (hasDQuote) {
			int idx = -2;
			while ((idx = sb.toString().indexOf('"', idx + 2)) != -1) {
				sb = sb.insert(idx, '"');
			}
		}
		sb.insert(0, '"');
		sb.append('"');
		return sb.toString();
	}

	/**
	 * @param inNum
	 * @param formatMask
	 * @return null if the input string or the format mask is null.
	 */
	public static String formatNumberStrNegativeWithBracket(String inNum, String formatMask, String prefix) {
		if (CommonUtil.isEmpty(inNum))
			return "";

		if (!NumberUtil.isValidNumber(inNum)) {
			return inNum;
		}

		if (CommonUtil.isEmpty(formatMask))
			return "";

		double val = new Double(inNum).doubleValue();

		String pre = "";
		String post = "";

		if (val < 0.000000000000000000000000000000000000) {
			pre = "(";
			post = ")";
		}

		if (prefix != null) {
			pre += prefix;
		}

		DecimalFormat myFormatter = new DecimalFormat(formatMask);
		String formattedStr = myFormatter.format(Math.abs(val));

		formattedStr = pre + formattedStr + post;

		// Logger.cruise(new CommonUtil(), "formatNumberStr(), formattedStr=" + formattedStr);
		return formattedStr;
	}

}